#include <iostream>
#include <memory>

class Fruit {
public:
    virtual void name() = 0;
};

class Apple : public Fruit {
public:
    virtual void name() override {
        std::cout << "apple\n";
    }
};

class Banana : public Fruit {
public:
    virtual void name() override {
        std::cout << "banana\n";
    }       
};
class Animal{
public:
    virtual void name() = 0;
};

class Dog : public Animal {
public:
    virtual void name() override {
        std::cout << "dog\n";
    }
};
class Cat : public Animal {
public:
    virtual void name() override {
        std::cout << "cat\n";
    }
};

class Factory {
public:
    virtual std::shared_ptr<Fruit> get_fruit(const std::string &name) = 0;
    virtual std::shared_ptr<Animal> get_animal(const std::string &name) = 0;
};
class FruitFactory : public Factory{
public:
    virtual std::shared_ptr<Fruit> get_fruit(const std::string &name) {
        if (name == "apple") {
            return std::make_shared<Apple>();
        }
        else {
            return std::make_shared<Banana>();
        }
    }
    virtual std::shared_ptr<Animal> get_animal(const std::string &name) {
        return std::shared_ptr<Animal>();
    }
};

class AnimalFactory : public Factory {
public:
    virtual std::shared_ptr<Animal> get_animal(const std::string &name) {
        if (name == "dog") {
            return std::make_shared<Dog>();
        }
        else {
            return std::make_shared<Cat>();
        }
    }
    virtual std::shared_ptr<Fruit> get_fruit(const std::string &name) {
        return std::shared_ptr<Fruit>();
    }
};

class FactoryProductor {
public:
    static std::shared_ptr<Factory> get_factory(const std::string &name) {
        if (name == "fruit") {
            return std::make_shared<FruitFactory>();
        }
        else {
            return std::make_shared<AnimalFactory>();
        }
    }
};

int main() {
    std::shared_ptr<Factory> factory = FactoryProductor::get_factory("fruit");
    std::shared_ptr<Fruit> fruit = factory->get_fruit("apple");
    fruit->name();
    fruit = factory->get_fruit("banana");
    fruit->name();

    factory = FactoryProductor::get_factory("animal");
    std::shared_ptr<Animal> animal = factory->get_animal("dog");
    animal->name();
    animal = factory->get_animal("cat");
    animal->name();
    return 0;
}
